import BaseMiddleware from './BaseMiddleware.js';
import ResponseFormatter from '../utils/ResponseFormatter.js';
import { config } from '../config.js';

/**
 * 授权中间件 - 处理用户权限和角色验证
 */
export class AuthorizationMiddleware extends BaseMiddleware {
    constructor(options = {}) {
        super({
            priority: 90, // 在认证之后执行
            defaultRole: 'user',
            adminRole: 'admin',
            superAdminRole: 'super_admin',
            ...options
        });
        
        // 权限映射表
        this.permissions = new Map();
        this.roleHierarchy = new Map();
        
        // 初始化默认权限和角色层次
        this.initializeDefaults();
    }

    /**
     * 初始化默认权限和角色层次
     */
    initializeDefaults() {
        // 设置角色层次（数字越大权限越高）
        this.roleHierarchy.set('guest', 0);
        this.roleHierarchy.set('user', 10);
        this.roleHierarchy.set('moderator', 20);
        this.roleHierarchy.set('admin', 30);
        this.roleHierarchy.set('super_admin', 40);

        // 设置默认权限
        this.setPermissions('user', [
            'user:read:own',
            'user:update:own',
            'product:read',
            'order:create',
            'order:read:own'
        ]);

        this.setPermissions('moderator', [
            'user:read',
            'product:create',
            'product:update',
            'order:read',
            'order:update'
        ]);

        this.setPermissions('admin', [
            'user:*',
            'product:*',
            'order:*',
            'system:read'
        ]);

        this.setPermissions('super_admin', [
            '*:*' // 所有权限
        ]);
    }

    /**
     * 执行授权检查
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @param {Function} next - Express next函数
     */
    async execute(req, res, next) {
        // 如果没有用户信息，说明认证失败或跳过了认证
        if (!req.user) {
            return ResponseFormatter.unauthorized(res, 'Authentication required for authorization');
        }

        // 获取用户角色和权限
        const userRoles = this.getUserRoles(req.user);
        const userPermissions = this.getUserPermissions(userRoles);
        
        // 将权限信息附加到请求对象
        req.userRoles = userRoles;
        req.userPermissions = userPermissions;
        
        // 记录授权信息
        this.logAuthorization(req, userRoles, userPermissions);
        
        next();
    }

    /**
     * 获取用户角色
     * @param {Object} user - 用户对象
     * @returns {Array} 用户角色数组
     */
    getUserRoles(user) {
        if (user.roles && Array.isArray(user.roles)) {
            return user.roles;
        }
        
        if (user.role) {
            return [user.role];
        }
        
        return [this.options.defaultRole];
    }

    /**
     * 获取用户权限
     * @param {Array} roles - 用户角色数组
     * @returns {Set} 用户权限集合
     */
    getUserPermissions(roles) {
        const permissions = new Set();
        
        roles.forEach(role => {
            const rolePermissions = this.permissions.get(role) || [];
            rolePermissions.forEach(permission => permissions.add(permission));
        });
        
        return permissions;
    }

    /**
     * 设置角色权限
     * @param {string} role - 角色名称
     * @param {Array} permissions - 权限数组
     */
    setPermissions(role, permissions) {
        this.permissions.set(role, permissions);
        console.log(`✓ Permissions set for role '${role}':`, permissions);
    }

    /**
     * 添加角色权限
     * @param {string} role - 角色名称
     * @param {string|Array} permissions - 权限或权限数组
     */
    addPermissions(role, permissions) {
        const existingPermissions = this.permissions.get(role) || [];
        const newPermissions = Array.isArray(permissions) ? permissions : [permissions];
        const updatedPermissions = [...new Set([...existingPermissions, ...newPermissions])];
        
        this.permissions.set(role, updatedPermissions);
        console.log(`✓ Permissions added to role '${role}':`, newPermissions);
    }

    /**
     * 移除角色权限
     * @param {string} role - 角色名称
     * @param {string|Array} permissions - 权限或权限数组
     */
    removePermissions(role, permissions) {
        const existingPermissions = this.permissions.get(role) || [];
        const permissionsToRemove = Array.isArray(permissions) ? permissions : [permissions];
        const updatedPermissions = existingPermissions.filter(p => !permissionsToRemove.includes(p));
        
        this.permissions.set(role, updatedPermissions);
        console.log(`✓ Permissions removed from role '${role}':`, permissionsToRemove);
    }

    /**
     * 检查用户是否有指定权限
     * @param {Request} req - Express请求对象
     * @param {string} permission - 权限字符串
     * @returns {boolean} 是否有权限
     */
    hasPermission(req, permission) {
        if (!req.userPermissions) {
            return false;
        }

        // 检查超级管理员权限
        if (req.userPermissions.has('*:*')) {
            return true;
        }

        // 检查精确匹配
        if (req.userPermissions.has(permission)) {
            return true;
        }

        // 检查通配符权限
        const [resource, action, scope] = permission.split(':');
        
        // 检查资源级通配符 (resource:*)
        if (req.userPermissions.has(`${resource}:*`)) {
            return true;
        }
        
        // 检查操作级通配符 (*:action)
        if (req.userPermissions.has(`*:${action}`)) {
            return true;
        }
        
        // 检查带作用域的通配符 (resource:action:*)
        if (scope && req.userPermissions.has(`${resource}:${action}:*`)) {
            return true;
        }

        return false;
    }

    /**
     * 检查用户是否有指定角色
     * @param {Request} req - Express请求对象
     * @param {string|Array} roles - 角色或角色数组
     * @returns {boolean} 是否有角色
     */
    hasRole(req, roles) {
        if (!req.userRoles) {
            return false;
        }

        const requiredRoles = Array.isArray(roles) ? roles : [roles];
        return requiredRoles.some(role => req.userRoles.includes(role));
    }

    /**
     * 检查用户角色等级是否满足要求
     * @param {Request} req - Express请求对象
     * @param {string} minRole - 最低角色要求
     * @returns {boolean} 是否满足角色等级
     */
    hasMinRole(req, minRole) {
        if (!req.userRoles) {
            return false;
        }

        const minLevel = this.roleHierarchy.get(minRole) || 0;
        const userMaxLevel = Math.max(...req.userRoles.map(role => this.roleHierarchy.get(role) || 0));
        
        return userMaxLevel >= minLevel;
    }

    /**
     * 检查资源所有权
     * @param {Request} req - Express请求对象
     * @param {Object} resource - 资源对象
     * @param {string} ownerField - 所有者字段名
     * @returns {boolean} 是否拥有资源
     */
    isResourceOwner(req, resource, ownerField = 'userId') {
        if (!req.user || !resource) {
            return false;
        }

        const userId = req.user.userId || req.user.id;
        const resourceOwnerId = resource[ownerField];
        
        return userId && resourceOwnerId && userId.toString() === resourceOwnerId.toString();
    }

    /**
     * 创建权限检查中间件
     * @param {string|Array} requiredPermissions - 必需的权限
     * @returns {Function} Express中间件函数
     */
    createPermissionMiddleware(requiredPermissions) {
        const permissions = Array.isArray(requiredPermissions) ? requiredPermissions : [requiredPermissions];
        
        return (req, res, next) => {
            if (!req.user) {
                return ResponseFormatter.unauthorized(res, 'Authentication required');
            }

            const hasAllPermissions = permissions.every(permission => this.hasPermission(req, permission));
            
            if (!hasAllPermissions) {
                this.logAuthorizationFailure(req, 'PERMISSION_DENIED', permissions);
                return ResponseFormatter.forbidden(res, 'Insufficient permissions');
            }

            next();
        };
    }

    /**
     * 创建角色检查中间件
     * @param {string|Array} requiredRoles - 必需的角色
     * @returns {Function} Express中间件函数
     */
    createRoleMiddleware(requiredRoles) {
        const roles = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
        
        return (req, res, next) => {
            if (!req.user) {
                return ResponseFormatter.unauthorized(res, 'Authentication required');
            }

            if (!this.hasRole(req, roles)) {
                this.logAuthorizationFailure(req, 'ROLE_DENIED', roles);
                return ResponseFormatter.forbidden(res, 'Insufficient role permissions');
            }

            next();
        };
    }

    /**
     * 创建最低角色等级检查中间件
     * @param {string} minRole - 最低角色要求
     * @returns {Function} Express中间件函数
     */
    createMinRoleMiddleware(minRole) {
        return (req, res, next) => {
            if (!req.user) {
                return ResponseFormatter.unauthorized(res, 'Authentication required');
            }

            if (!this.hasMinRole(req, minRole)) {
                this.logAuthorizationFailure(req, 'MIN_ROLE_DENIED', minRole);
                return ResponseFormatter.forbidden(res, `Minimum role '${minRole}' required`);
            }

            next();
        };
    }

    /**
     * 创建资源所有权检查中间件
     * @param {Function} resourceGetter - 获取资源的函数
     * @param {string} ownerField - 所有者字段名
     * @returns {Function} Express中间件函数
     */
    createOwnershipMiddleware(resourceGetter, ownerField = 'userId') {
        return async (req, res, next) => {
            if (!req.user) {
                return ResponseFormatter.unauthorized(res, 'Authentication required');
            }

            try {
                const resource = await resourceGetter(req);
                
                if (!resource) {
                    return ResponseFormatter.notFound(res, 'Resource not found');
                }

                // 管理员可以访问所有资源
                if (this.hasMinRole(req, this.options.adminRole)) {
                    return next();
                }

                // 检查所有权
                if (!this.isResourceOwner(req, resource, ownerField)) {
                    this.logAuthorizationFailure(req, 'OWNERSHIP_DENIED', resource.id);
                    return ResponseFormatter.forbidden(res, 'Access denied: not resource owner');
                }

                // 将资源附加到请求对象
                req.resource = resource;
                next();
            } catch (error) {
                console.error('[AuthorizationMiddleware] Ownership check error:', error);
                return ResponseFormatter.error(res, 'Authorization check failed', 500);
            }
        };
    }

    /**
     * 记录授权日志
     * @param {Request} req - Express请求对象
     * @param {Array} roles - 用户角色
     * @param {Set} permissions - 用户权限
     */
    logAuthorization(req, roles, permissions) {
        if (config.log.console && this.options.debug) {
            console.log(`[AuthorizationMiddleware][SUCCESS]`, {
                userId: req.user.userId || req.user.id,
                roles,
                permissionCount: permissions.size,
                method: req.method,
                url: req.originalUrl,
                timestamp: new Date().toISOString()
            });
        }
    }

    /**
     * 记录授权失败日志
     * @param {Request} req - Express请求对象
     * @param {string} reason - 失败原因
     * @param {*} details - 详细信息
     */
    logAuthorizationFailure(req, reason, details) {
        if (config.log.console) {
            console.warn(`[AuthorizationMiddleware][${reason}]`, {
                userId: req.user?.userId || req.user?.id || 'unknown',
                userRoles: req.userRoles || [],
                details,
                method: req.method,
                url: req.originalUrl,
                ip: this.getClientIP(req),
                timestamp: new Date().toISOString()
            });
        }
    }

    /**
     * 获取所有权限信息
     * @returns {Object} 权限信息
     */
    getPermissionsInfo() {
        const info = {
            roles: {},
            hierarchy: Object.fromEntries(this.roleHierarchy)
        };

        this.permissions.forEach((permissions, role) => {
            info.roles[role] = permissions;
        });

        return info;
    }
}

// 创建默认实例
export const authorizationMiddleware = new AuthorizationMiddleware();

// 导出便捷方法
export const authorize = () => authorizationMiddleware.getMiddleware();
export const requirePermission = (permissions) => authorizationMiddleware.createPermissionMiddleware(permissions);
export const requireRole = (roles) => authorizationMiddleware.createRoleMiddleware(roles);
export const requireMinRole = (minRole) => authorizationMiddleware.createMinRoleMiddleware(minRole);
export const requireOwnership = (resourceGetter, ownerField) => authorizationMiddleware.createOwnershipMiddleware(resourceGetter, ownerField);

export default AuthorizationMiddleware;